from microWebSrv import MicroWebSrv
import logging
import os


logging.basicConfig(logging.DEBUG)
log = logging.getLogger("main")


# os.chdir("D:\project/esp32_git/esp32/")
# ----------------------------------------------------------------------------
@MicroWebSrv.route('/')
def _httpHandlerHome(httpClient, httpResponse):
    log.debug(os.getcwd())
    with open(os.getcwd() + "/index.html", "r", encoding='UTF-8') as f:
        content = f.read()

    httpResponse.WriteResponseOk(headers=None,
                                 contentType="text/html",
                                 contentCharset="UTF-8",
                                 content=content)


@MicroWebSrv.route('/css/demo.css')
def _httpHandlerHome(httpClient, httpResponse):
    httpResponse.WriteResponseFile("httpserver/css/demo.css", contentType="text/css", headers=None)


@MicroWebSrv.route('/js/jquery.ffform.js')
def _httpHandlerHome(httpClient, httpResponse):
    httpResponse.WriteResponseFile("httpserver/js/jquery.ffform.js", contentType="text/javascript", headers=None)


@MicroWebSrv.route('/js/jquery-1.10.2.min.js')
def _httpHandlerHome(httpClient, httpResponse):
    httpResponse.WriteResponseFile("httpserver/js/jquery-1.10.2.min.js", contentType="text/javascript", headers=None)


@MicroWebSrv.route('/test')
def _httpHandlerTestGet(httpClient, httpResponse):
    content = """\
	<!DOCTYPE html>
	<html lang=en>
        <head>
        	<meta charset="UTF-8" />
            <title>TEST GET</title>
        </head>
        <body>
            <h1>TEST GET</h1>
            Client IP address = %s
            <br />
			<form action="/test" method="post" accept-charset="ISO-8859-1">
				First name: <input type="text" name="firstname"><br />
				Last name: <input type="text" name="lastname"><br />
				<input type="submit" value="Submit">
			</form>
        </body>
    </html>
	""" % httpClient.GetIPAddr()
    httpResponse.WriteResponseOk(headers=None,
                                 contentType="text/html",
                                 contentCharset="UTF-8",
                                 content=content)


@MicroWebSrv.route('/', 'POST')
def _httpHandlerTestPost(httpClient, httpResponse):
    httpResponse.WriteResponseJSONOk(obj=None, headers=None)


@MicroWebSrv.route('/update/local', 'POST')
def _httpHandlerTestPost(httpClient, httpResponse):
    content = httpClient.ReadRequestContent()
    content

# @MicroWebSrv.route('/update/remote', 'GET')
# def _httpHandlerTestPost(httpClient, httpResponse):
#     Update().start()


@MicroWebSrv.route('/test', 'POST')
def _httpHandlerTestPost(httpClient, httpResponse):
    formData = httpClient.ReadRequestPostedFormData()
    firstname = formData["firstname"]
    lastname = formData["lastname"]
    content = """\
	<!DOCTYPE html>
	<html lang=en>
		<head>
			<meta charset="UTF-8" />
            <title>TEST POST</title>
        </head>
        <body>
            <h1>TEST POST</h1>
            Firstname = %s<br />
            Lastname = %s<br />
        </body>
    </html>
	""" % (MicroWebSrv.HTMLEscape(firstname),
           MicroWebSrv.HTMLEscape(lastname))
    httpResponse.WriteResponseOk(headers=None,
                                 contentType="text/html",
                                 contentCharset="UTF-8",
                                 content=content)


@MicroWebSrv.route('/edit/<index>')  # <IP>/edit/123           ->   args['index']=123
@MicroWebSrv.route('/edit/<index>/abc/<foo>')  # <IP>/edit/123/abc/bar   ->   args['index']=123  args['foo']='bar'
@MicroWebSrv.route('/edit')  # <IP>/edit               ->   args={}
def _httpHandlerEditWithArgs(httpClient, httpResponse, args={}):
    content = """\
	<!DOCTYPE html>
	<html lang=en>
        <head>
        	<meta charset="UTF-8" />
            <title>TEST EDIT</title>
        </head>
        <body>
	"""
    content += "<h1>EDIT item with {} variable arguments</h1>" \
        .format(len(args))

    if 'index' in args:
        content += "<p>index = {}</p>".format(args['index'])

    if 'foo' in args:
        content += "<p>foo = {}</p>".format(args['foo'])

    content += """
        </body>
    </html>
	"""
    httpResponse.WriteResponseOk(headers=None,
                                 contentType="text/html",
                                 contentCharset="UTF-8",
                                 content=content)


# ----------------------------------------------------------------------------

def _acceptWebSocketCallback(webSocket, httpClient):
    print("WS ACCEPT")
    webSocket.RecvTextCallback = _recvTextCallback
    webSocket.RecvBinaryCallback = _recvBinaryCallback
    webSocket.ClosedCallback = _closedCallback


def _recvTextCallback(webSocket, msg):
    print("WS RECV TEXT : %s" % msg)
    webSocket.SendText("Reply for %s" % msg)


def _recvBinaryCallback(webSocket, data):
    print("WS RECV DATA : %s" % data)


def _closedCallback(webSocket):
    print("WS CLOSED")


# ----------------------------------------------------------------------------

# routeHandlers = [
#	( "/test",	"GET",	_httpHandlerTestGet ),
#	( "/test",	"POST",	_httpHandlerTestPost )
# ]
def t():
    d ={}
    name =""
    filename=""
    head = 0
    b = b'------WebKitFormBoundarykI4yAGNWQA0u8lDX\r\nContent-Disposition: form-data; name="name"; filename="client.py"\r\nContent-Type: application/octet-stream\r\n\r\n#!/usr/bin/env python3\n\nfrom aiocoap import resource, error\nfrom aiocoap.message import Message\nfrom aiocoap.numbers.codes import Code\nfrom aiocoap.protocol import Context\nfrom aiocoap.resource import ObservableResource\n\nfrom encdec import PayloadEncoder, PayloadDecoder\nfrom handlers import *\nfrom model import ClientModel\n\nlogging.basicConfig(level=logging.DEBUG,\n                    format=\'%(asctime)s [%(levelname)s] %(message)s\')\nlog = logging.getLogger(\'client\')\n\n\nclass RequestHandler(ObservableResource):\n    def __init__(self, model, encoder, decoder):\n        super(RequestHandler, self).__init__()\n        self.model = model\n        self.encoder = encoder\n        self.decoder = decoder\n\n    def handle_read(self, path):\n        return self.encoder.encode(path)\n\n    def handle_write(self, path, payload, content_format):\n        return self.decoder.decode(path, payload, content_format)\n\n    def handle_observe(self, path, request):\n        plen = len(path)\n        if plen == 1:\n            obs = f\'observe_{path[0]}\'\n        elif plen == 2:\n            obs = f\'observe_{path[0]}_{path[1]}\'\n        elif plen == 3:\n            obs = f\'observe_{path[0]}_{path[1]}_{path[2]}\'\n        else:\n            return Message(code=Code.BAD_REQUEST)\n\n        def _notifier():\n            self.updated_state(response=self.encoder.encode(path))\n\n        try:\n            obs_method = eval(obs)\n            cancel = request.opt.observe == \'0\'\n            _kwargs = dict(model=self.model,\n                           path=path,\n                           payload=request.payload,\n                           content_format=request.opt.content_format,\n                           cancel=cancel,\n                           notifier=_notifier)\n            obs_method(None, **_kwargs)\n            return self.encoder.encode(path)\n        except NameError:\n            pass\n        return Message(code=Code.METHOD_NOT_ALLOWED)\n\n    def handle_exec(self, path, request):\n        if len(path) != 3 or not self.model.is_path_valid(path):\n            return Message(code=Code.BAD_REQUEST)\n        if not self.model.is_resource_executable(path[0], path[1], path[2]):\n            return Message(code=Code.METHOD_NOT_ALLOWED)\n        _op = str(self.model.resource(path[0], path[1], path[2]))\n        try:\n            _op_method = eval(_op)\n        except NameError:\n            log.error(\n                f\'handler "{_op}" for {"/".join(path)} is not implemented. Please implement it in handlers.py\')\n            return Message(code=Code.NOT_IMPLEMENTED)\n        _kwargs = dict(model=self.model, payload=request.payload,\n                       path=path, content_format=request.opt.content_format)\n        result = _op_method(None, **_kwargs)\n        return Message(code=Code.CHANGED, payload=result) if result is not None else Message(code=Code.CHANGED)\n\n    async def render(self, req):\n        path, request = req\n        m = getattr(self, \'render_%s\' % str(request.code).lower(), None)\n        if not m:\n            raise error.UnallowedMethod()\n        return await m(path, request)\n\n    async def render_get(self, path, request):\n        if request.opt.observe is not None:\n            log.debug(f\'observe on {"/".join(path)}\')\n            return self.handle_observe(path, request)\n        else:\n            log.debug(f\'read on {"/".join(path)}\')\n            return self.handle_read(path)\n\n    async def render_put(self, path, request):\n        log.debug(f\'write on {"/".join(path)}\')\n        message, _decoded = self.handle_write(\n            path, request.payload, request.opt.content_format)\n        if message.code == Code.CHANGED:\n            self.model.apply(_decoded)\n        return message\n\n    async def render_post(self, path, request):\n        log.debug(f\'execute on {"/".join(path)}\')\n        return self.handle_exec(path, request)\n\n\nclass Client(resource.Site):\n    endpoint = \'python-client\'\n    binding_mode = \'UQ\'\n    lifetime = 86400  # default: 86400\n    context = None\n    rd_resource = None\n\n    def __init__(self, model=ClientModel(), server=\'localhost\', server_port=5683):\n        super(Client, self).__init__()\n        self.server = server\n        self.server_port = server_port\n        self.model = model\n        self.encoder = PayloadEncoder(model)\n        self.decoder = PayloadDecoder(model)\n        self.request_handler = RequestHandler(\n            self.model, self.encoder, self.decoder)\n        for path in model.instance_iter():\n            self.add_resource(path, self.request_handler)\n        for path in model.resource_iter():\n            self.add_resource(path, self.request_handler)\n\n    async def render(self, request):\n        uri_path = request.opt.uri_path\n        if len(uri_path) == 0:\n            return await super().render(request)\n        else:\n            return await self.request_handler.render((uri_path, request,))\n\n    async def update_register(self):\n        log.debug(\'update_register()\')\n        update = Message(code=Code.POST)\n        update.opt.uri_host = self.server\n        update.opt.uri_port = self.server_port\n        update.opt.uri_path = (\'rd\', self.rd_resource)\n        response = await self.context.request(update).response\n        if response.code != Code.CHANGED:\n            # error while update, fallback to re-register\n            log.warning(\n                f\'failed to update registration, code {response.code}, falling back to registration\')\n            asyncio.ensure_future(self.run())\n        else:\n            log.info(f\'updated registration for {self.rd_resource}\')\n            # yield to next update - 1 sec\n            await asyncio.sleep(self.lifetime - 1)\n            asyncio.ensure_future(self.update_register())\n\n    async def run(self):\n        self.context = await Context.create_server_context(self, bind=(\'localhost\', 0))\n\n        # send POST (registration)\n        request = Message(code=Code.POST, payload=\',\'.join(\n            self.model.get_object_links()).encode())\n        request.opt.uri_host = self.server\n        request.opt.uri_port = self.server_port\n        request.opt.uri_path = (\'rd\',)\n        request.opt.uri_query = (\n            f\'ep={self.endpoint}\', f\'b={self.binding_mode}\', f\'lt={self.lifetime}\')\n        response = await self.context.request(request).response\n\n        # expect ACK\n        if response.code != Code.CREATED:\n            raise BaseException(\n                f\'unexpected code received: {response.code}. Unable to register!\')\n\n        # we receive resource path (\'rd\', \'xyz...\')\n        self.rd_resource = response.opt.location_path[1]\n        log.info(f\'client registered at location {self.rd_resource}\')\n        await asyncio.sleep(self.lifetime - 1)\n        asyncio.ensure_future(self.update_register())\n\n\nif __name__ == \'__main__\':\n    client = Client()\n    loop = asyncio.get_event_loop()\n    asyncio.ensure_future(client.run())\n    try:\n        loop.run_forever()\n    except KeyboardInterrupt:\n        loop.close()\n        exit(0)\n\r\n------WebKitFormBoundarykI4yAGNWQA0u8lDX--\r\n'
    content_str = b.decode()
    s = 'multipart/form-data; boundary=----WebKitFormBoundarykI4yAGNWQA0u8lDX'
    content_len = len(b)
    boundary = s.split("=")[1]

    if not boundary in content_str[:100]:
        return (False, "Content NOT begin with boundary")
    head += content_str.find("\r\n") + 2

t()

srv = MicroWebSrv(webPath='/', port=1235)
srv.MaxWebSocketRecvLen     = 256
srv.WebSocketThreaded		= False
srv.AcceptWebSocketCallback = _acceptWebSocketCallback
# srv.SetNotFoundPageUrl("http://my-device.wifi")
srv.Start()

# ----------------------------------------------------------------------------
